home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / util / boot / appvm.lha / AppVM / appvm.s < prev    next >
Text File  |  1994-01-28  |  54KB  |  1,668 lines

  1. *************************************************************************************
  2. *
  3. * AppVM ®    (Application VIRTUAL MEMORY)        © Copyright LVA March 1992
  4. * -------                        --------------------------
  5. *
  6. * Written by Laurence Vanhelsuwé.
  7. *
  8. *
  9. * AppVM ® is a stop-gap solution for application writers who need UNIX-style
  10. * Demand Paged Virtual Memory.
  11. * This program extends the functionality of Exec's AllocMem() and FreeMem() and
  12. * AmigaDOS's Read() and Write().
  13. * Only Processes can use VM, not Tasks !
  14. *
  15. * This implementation behaves like an exclusive resource like PAR: or SER: as
  16. * opposed to a shared resource. A single Process at a time can allocate (and use)
  17. * areas of memory that are larger than physical RAM memory as if that memory was
  18. * physically present.
  19. * As soon as this unique Process (referred to in the source as the "client") frees
  20. * all its VM, another client can immediately start using the resource again.
  21. *
  22. * This program is called Application VM because the system (Exec, Intuition)
  23. * is never allowed to handle VM pointers.
  24. * Only applications are able to get VM and use it "internally", i.e. they are not
  25. * allowed to pass a VM ptr to the system (via a call to DoIO() for example).
  26. *  (More precisely, bus error exceptions due to the dereferencing of VM ptrs are
  27. *  only handled correctly if the code trapping is in the scope of the client Process.)
  28. *
  29. * There's one important exception to this rule:
  30. * Exec's AllocMem() is the source of VM ptrs and FreeMem(), Read() and Write() can
  31. * all handle VM ptrs.
  32. * This should be enough for any application (who gets the status of "client") to
  33. * process huge amounts of data and load and/or save into/from VM.
  34. *
  35. * History
  36. * -------
  37. * 24/MAR/92:    started code    (goal: getting the Amiga to use my new MMU tree)
  38. * 25/MAR/92:            (goal: getting instructions which use VM to restart)
  39. * 26/MAR/92:            (goal: getting a client Process to use service)
  40. * 27/MAR/92:            (goal: full service incl. Read()/Write() )
  41. * 29/APR/92: fixed double Close() bug in case disk full
  42. *
  43. *************************************************************************************
  44.  
  45.         include    std
  46.         include    hardware/custom.i
  47.         include    exec/vmemory.i        ;include our new VM include!
  48.  
  49.  
  50. ;-----------------------------------------------
  51. ; Program Global Constants
  52. ;-----------------------------------------------
  53.  
  54. ; This version allows a maximum VM request of 256Mb (if you've got that much spare
  55. ; on your hard disk). The code can handle more though. **!! (How much, 2 Gb ?)
  56. ; The absolute maximum in any case is 2 Gigabytes since VM addresses start at
  57. ; $80000000.
  58.  
  59. MAX_VM_MEGS    equ    256            ;256Mb max LA range
  60.  
  61. ; Since we're only using a single B-level table for the VM logical addresses (which
  62. ; have bit31=1), I can only map a maximum VM range of 256Mb.
  63. ; That should be enough since you also need that much space on your hard disk!
  64.  
  65. KILOBYTE    equ    1024
  66. MEGABYTE    equ    KILOBYTE*KILOBYTE
  67.  
  68. PAGE_SHIFT    equ    15            ;2^15 = 32K
  69. PAGE_SIZE    equ    1<<PAGE_SHIFT        ;one PAGE is 32K big
  70.  
  71. ; Pages are this large because:
  72. ;
  73. ; 1) AmigaDOS is very efficient at transfering large chuncks from/to disk.
  74. ; 2) Bus exception errors become less frequent.
  75. ; 4) The D-level table shrinks significantly.
  76. ; 3) The free pages bitmap shrinks too.
  77.  
  78.  
  79. VM_START    equ    $80000000        ;all VM addresses have b31=1
  80.  
  81. ; What this program does is to create a new MMU table which CONTAINS the standard
  82. ; 2-level (A,B) Exec MMU table and a new branch for VM addresses.
  83. ; The standard table uses TIA=8 and TIB=6 with a table A index LIMIT of 16.
  84. ; This means that the standard table provides translation for the very first 256Mb
  85. ; of address space in the Amiga. Everything above it is off-limit (BUS ERROR).
  86.  
  87. ; What AppVM does is to "shift down" this tree and turn it into a branch of a bigger
  88. ; tree using the following LA field subdivisions:
  89.  
  90.             ;    TABLE  ENTRIES    PER ENTRY
  91.             ;    -----  -------    ---------
  92.  
  93. TIA        equ    4    ;  4Gb 16     = 256 Mb
  94. TIB        equ    4    ;256Mb 16     =  16 Mb
  95. TIC        equ    6    ; 16Mb 64     = 256 K
  96. TID        equ    3    ;256K   8     =  32 K PAGES
  97.  
  98. ; Check whether chosen logical address breakdown fields are legal.
  99.  
  100. TC_CHECK    equ    32-(TIA+TIB+TIC+TID+PAGE_SHIFT)
  101.  
  102.     IFNE    TC_CHECK
  103.  blabla    ; ** WARNING ** SELECTED LA INDEX BREAK-DOWN IS INVALID
  104.     END
  105.     ENDC
  106.  
  107. ; The new TIB,TIC values have to be derived from the TIA,TIB values of the original
  108. ; translation tree. TIC has to be the old TIB. TIB Can be 4 instead the original
  109. ; TIA's 8 because the original A-table is LIMITED to the first 16 indices.
  110. ; This is necessary so that I can retain the existing MMU translation tree as a
  111. ; branch of my bigger tree (which is now a 4-level tree).
  112.  
  113.  
  114. *####################################################################################
  115. *
  116. * RESULTING MMU TRANSLATION TREE STRUCTURE: 
  117. * =========================================
  118. *
  119. *    A-table (one for ENTIRE SYSTEM)
  120. *
  121. *   ____________
  122. * 0 |_1st 256Mb|------> STANDARD Exec MMU table (becomes levels B and C)
  123. * 1 |          |
  124. * 2 |          |
  125. * 3 |          |
  126. * 4 |          |
  127. * 5 |          |
  128. * 6 |          |
  129. * 7 |          |
  130. * 8 |_8th 256Mb|------> VM B-table
  131. * 9 |          |        ____________
  132. * A |          |        | 1st 16Mb |------> 1st VM C-table
  133. * B |          |        | 2nd 16Mb |         ______________
  134. * C |          |        | 3rd 16Mb |         | 1st 256K   |-----> 1st VM D-table
  135. * D |          |        | 4th 16Mb |         | 2nd 256K   |       _______________
  136. * E |          |        | 5th 16Mb |         |            |       | 1st 32K PAGE |
  137. * F |          |        | 6th 16Mb |         :            :       | 2nd 32K PAGE |
  138. *   ------------        | 7th 16Mb |                              | 3rd 32K PAGE |
  139. * All other ranges      | 8th 16Mb |           64 entries         | 4th 32K PAGE |
  140. * are INVALID.          | 9th 16Mb |                              | 5th 32K PAGE |
  141. *                       |10th 16Mb |         :            :       | 6th 32K PAGE |
  142. *                       |11th 16Mb |         |            |       | 7th 32K PAGE |
  143. *                       |12th 16Mb |         | 63rd 256K  |       | 8th 32K PAGE |
  144. *                       |13th 16Mb |         | 64th 256K  |       ----------------
  145. *                       |14th 16Mb |         --------------
  146. *                       |15th 16Mb |
  147. *                       |16th 16Mb |
  148. *                       ------------
  149. *####################################################################################
  150.  
  151. A_TSIZE    equ    (1<<TIA)*4    ;64    ;size of one table at each level
  152. B_TSIZE    equ    (1<<TIB)*4    ;64    ;(using short descriptors)
  153. C_TSIZE    equ    (1<<TIC)*4    ;256
  154. D_TSIZE    equ    (1<<TID)*4    ;32
  155.  
  156. C_TABLES    equ    1<<TIB            ;number of C tables depends on B level
  157. D_TABLES    equ    1<<(TIB+TIC)        ;1024 of them ! (8192 descriptors)
  158.  
  159. TREE_SIZE    equ    A_TSIZE+B_TSIZE+(C_TABLES*C_TSIZE)+(D_TABLES*D_TSIZE)
  160.             ; 64   +  64   +       4096       +     32768
  161.  
  162. SHORT_INVALID    equ    $BAD00000        ;DT bits = 00 = INVALID
  163.                     ;this descriptor HAS to have b31=1 (quick test)
  164.  
  165. PTR_MASK    equ    $FFFFFF00        ;low descriptor byte is not part of ptr
  166.  
  167. MODIFIED_PAGE    equ    4            ;bit set if page has been written to
  168. ACCESSED_PAGE    equ    3            ;bit set if page has been accessed (R/W)
  169.  
  170. DT_INVALID    equ    $0
  171. DT_PAGE        equ    $1
  172. DT_VALID_4BYTE    equ    $2            ;table pointer points to short table
  173. DT_VALID_8BYTE    equ    $3            ;table pointer points to short table
  174.  
  175. TC_ENABLE    equ    1<<31
  176. TC_PSIZE    equ    (%1111)<<20        ;select 32K pages
  177. TC_TIA        equ    TIA<<12
  178. TC_TIB        equ    TIB<<8
  179. TC_TIC        equ    TIC<<4
  180. TC_TID        equ    TID
  181.  
  182. NEW_TC    equ    TC_ENABLE+TC_PSIZE+TC_TIA+TC_TIB+TC_TIC+TC_TID
  183.  
  184. _intena        equ    $dff000+intena        ;for DISABLE/ENABLE
  185.  
  186. ;##########################################################################
  187.  
  188. START_APPVM:    move.l    sp,stack_level        ;store original sp
  189.         move.l    a0,arg_line        ;store raw arguments ptr
  190.  
  191.         bsr    init_all        ;init vars, open DOS, stdout
  192.         beq    bail_out        ;if couldn't open something: exit now
  193.  
  194.         move.l    4.w,a6            ;check to see that this machine is
  195.         move.w    AttnFlags(a6),d0    ;at least 030 based coz I need MMU
  196.         btst    #AFB_68030,d0        ;(**!! SIMPLISTIC TEST: tst mmu config!)
  197.         beq    need_MMU
  198.  
  199.         bsr    parse_args        ;get arguments (VM size, swapfile name)
  200.  
  201.         cmp.l    #$00FFFFFF,$8        ;has other copy of APPVM already been
  202.         bhi    already_resident    ;started ? (**!! SIMPLISTIC TEST)
  203.  
  204.         bsr    create_swapfile        ;create swapfile on disk
  205.  
  206.         bsr    init_VM_pool        ;VM logical address range management
  207.         beq    no_VM_init
  208.  
  209.         bsr    install_patches        ;modify system to handle VM accesses
  210.  
  211.         lea    VM_ready,a0        ;"Virtual Memory Manager 0.9 Ready"
  212.         bsr    print_error
  213.  
  214.         move.l    4.w,a6            ;using exec library
  215.         move.l    #SIGBREAKF_CTRL_F,d0    ;Wait() until explicitly killed
  216.         EXEC    Wait            ;using BREAK PROCESS x F
  217.  
  218. ; At this stage this Process falls asleep but its code can temporarily come to life
  219. ; when there are bus errors or when other Processes call AllocMem() or FreeMem().
  220.  
  221. bail_out    bsr    unpatch_all        ;return Alloc/FreeMem to normal.
  222.  
  223.         lea    VM_off,a0        ;"Virtual Memory Manager no longer active"
  224.         bsr    print_error
  225.  
  226.         move.l    4.w,a6            ;using Exec
  227.  
  228.         move.l    vm_tree,d0        ;did we ever allocate the VM tree ?
  229.         beq    no_tree
  230.         move.l    d0,a1
  231.         move.l    #TREE_SIZE,d0
  232.         EXEC    FreeMem
  233.  
  234. no_tree        move.l    vm_bitmap,d0        ;dealloc pages bitmap
  235.         beq    no_bitmap
  236.         move.l    d0,a1
  237.         move.l    bitmap_size,d0
  238.         EXEC    FreeMem
  239.  
  240. no_bitmap    bsr     close_all        ;used libraries, handles
  241.  
  242. END_APPVM:    move.l    stack_level,sp        ;restore sp to original
  243.         rts
  244.  
  245. ;##########################################################################
  246.  
  247. ;-----------------------------------------------
  248. ; ERROR PRINTING ROUTINES
  249. ;-----------------------------------------------
  250. no_table    lea    no_table_str,a0
  251.         bsr    print_error
  252.         bra    bail_out
  253. ;-----------------------------------------------
  254. give_example    lea    give_example_str,a0
  255.         bsr    print_error
  256.         bra    bail_out
  257. ;-----------------------------------------------
  258. too_much_vm    lea    too_much_vm_str,a0
  259.         bsr    print_error
  260.         bra    bail_out
  261. ;-----------------------------------------------
  262. not_enough_vm    lea    not_enough_vm_str,a0
  263.         bsr    print_error
  264.         bra    bail_out
  265. ;-----------------------------------------------
  266. no_VM_init    lea    no_VM_init_str,a0
  267.         bsr    print_error
  268.         bra    bail_out        
  269. ;-----------------------------------------------
  270. unable_to_create lea    unable_to_create_str,a0
  271.         bsr    print_error
  272.         bra    bail_out        
  273. ;-----------------------------------------------
  274. disk_full    lea    disk_full_str,a0
  275.         bsr    print_error
  276.         bra    bail_out
  277. ;-----------------------------------------------
  278. already_resident lea    resident_str,a0
  279.         bsr    print_error
  280.         bra    bail_out
  281. ;-----------------------------------------------
  282. need_MMU    lea    need_MMU_str,a0
  283.         bsr    print_error
  284.         bra    bail_out
  285.  
  286. ;-----------------------------------------------
  287. ; Check user arguments.
  288. ;
  289. ; Template: VMMEGS/A,SWAPFILE/K
  290. ;-----------------------------------------------
  291.  
  292. parse_args    move.l    #default_swfn,swap_filename    ;set default filename
  293.  
  294.         move.l    #APPVM_template,d1
  295.         move.l    #appvm_results,d2
  296.         bsr    ReadArgs        ;parse args according to template
  297.         beq    give_example
  298.  
  299.         move.l    vm_megs,a0        ;get pointer to REQUIRED VM size arg
  300.         bsr    DEC_TO_BIN        ;convert from string to binary
  301.         cmp.l    #MAX_VM_MEGS,d1        ;reasonable size request ?
  302.         bhi    too_much_vm
  303.  
  304.         moveq    #20,d0            ;turn into bytes (2^20 = 1Meg)
  305.         lsl.l    d0,d1
  306.         move.l    d1,vm_bytes        ;remember size of VM to manage
  307.         beq    not_enough_vm
  308.  
  309.         rts        
  310. ;-----------------------------------------------
  311. ; Create a "swap partition on hard disk".
  312. ; This is actually just any old AmigaDOS file on any device.
  313. ;-----------------------------------------------
  314.  
  315. create_swapfile    move.l    DOS_LIB_PTR,a6        ;using DOS..
  316.  
  317.         move.l    swap_filename,d1
  318.         move.l    #MODE_OLDFILE,d2    ;assume file already exists..
  319.         DOS    Open            ;open for R/W accesses
  320.         move.l    d1,swap_fhandle
  321.         bne    set_size
  322.  
  323.         move.l    swap_filename,d1    ;if not then create fresh.
  324.         move.l    #MODE_NEWFILE,d2
  325.         DOS    Open
  326.         move.l    d1,swap_fhandle
  327.         beq    unable_to_create    ;exit if that didn't work either!
  328. ;---------------
  329. set_size    move.l    vm_bytes,d2        ;force existing file to be large
  330.         move.l    #OFFSET_BEGINNING,d3    ;enough for our VM range
  331.         DOS    SetFileSize        ;(shrink or stretch)
  332.         cmp.l    d2,d0
  333.         bne    no_stretch        ;did sizing work ?
  334.  
  335.         rts
  336. ;-----------------------------------------------
  337. ; Couldn't create such a large file on disk.
  338. ; Close file and Delete it before reporting failure.
  339. ;-----------------------------------------------
  340. no_stretch    move.l    swap_fhandle,d1        ;free lock on file
  341.         DOS    Close
  342.  
  343.         move.l    swap_filename,d1
  344.         DOS    DeleteFile        ;remove it (otherwise disk 100% full)
  345.  
  346.         clr.l    swap_fhandle        ;tell cleanup() we've done it.
  347.         bra    disk_full
  348.  
  349. ;-----------------------------------------------------------------------------------
  350. ; Allocate a fresh RAM page so that a new VM page can be enabled and loaded
  351. ; from disk.
  352. ; If no external RAM is available, then go through D-table descriptors and
  353. ; find any page which hasn't been modified yet and rob it to satisfy our need.
  354. ; If all pages have been modified, then take the first page and swap it out
  355. ; to disk (last resort).
  356. ;
  357. ; This routine is the USER mode part of the exception handler.
  358. ;
  359. ; naughty_vm_ptr -> VM address that caused the bus error exception
  360. ;-----------------------------------------------------------------------------------
  361.  
  362. add_VM_page    bsr    age_pages        ;**!! should be in IRQ
  363.  
  364.         move.l    naughty_vm_ptr,d0
  365.         and.l    #~(PAGE_SIZE-1),d0
  366.         move.l    d0,naughty_vm_ptr    ;calc aligned VM PAGE address
  367.  
  368.         move.l    #PAGE_SIZE,d7        ;get RAM aligned to a page boundary
  369.         move.l    #PAGE_SIZE,d0        ;size of allocation
  370.         bsr    alloc_aligned        ;get fresh page
  371.         move.l    d0,d7            ;store addr in parm for enable_page
  372.         beq    running_low        ;if succeeded,
  373. ;---------------
  374. localize_page    move.l    naughty_vm_ptr,a2    ;-> VM addr at which
  375.         move.l    d7,a3            ;this RAM page should appear.
  376.         bsr    load_page        ;fill page from copy on swapdevice
  377.         bsr    enable_page        ;and change MMU table to enable page
  378.  
  379. return_to_excep    lea    bus_error_tail,a5    ;-> continuation point of exc. handler
  380.         move.l    4.w,a6
  381.         EXEC    Supervisor        ;finish off and never come back here
  382.  
  383. ;         -- WE NEVER RETURN HERE --
  384.  
  385.  
  386. ************************************************************************************
  387.  
  388. ;----------------------------------------------------------------------
  389. ; Can't allocate a page from RAM, so steal a page from MMU tree itself.
  390. ; There's always at least one mapped page in the tree. **!!
  391. ;----------------------------------------------------------------------
  392.  
  393. running_low    move.l    D_tables,a0        ;-> list of page descriptors
  394.  
  395.         moveq    #0,d0
  396.         bset    #TIB+TIC+TID,d0        ;total # of descriptors in D-tables
  397.  
  398. find_unmodified    move.l    (a0)+,d7        ;get a page descriptor
  399.  
  400.         bclr    #0,d7            ;is this a valid page ?
  401.         beq    bad_page        ;yes, 
  402.  
  403.         move.l    d7,d6            ;remember any valid page for worse case
  404.         move.l    a0,d5            ;and remember associated VM address !
  405.  
  406.         bclr    #ACCESSED_PAGE,d7    ;is this an old page ?
  407.         bne    bad_page        ;yep,
  408.  
  409.         bclr    #MODIFIED_PAGE,d7    ;is this page still virgin ?
  410.         beq    rob_page        ;no,
  411.  
  412. bad_page    sub.l    #1,d0            ;more descriptors available ?
  413.         bne    find_unmodified        ;no, use last valid page regardless then
  414.  
  415.         and.l    #PTR_MASK,d6        ;isolate robbed dirty page address
  416.  
  417.         move.l    d5,d0            ;descr address in D-table (+4)
  418.  
  419.         sub.l    #4,d0            ;undo descriptor scan postincrement
  420.         sub.l    D_tables,d0        ;= VM page #  (*4)
  421.         moveq    #PAGE_SHIFT-2,d1    ;(-2 because already multiplied by 4)
  422.         lsl.l    d1,d0            ;VM byte offset
  423.         add.l    #VM_START,d0        ;-> valid VM address
  424.  
  425.         move.l    d0,a2
  426.         move.l    d6,a3            ;before robbing dirty page: save it to
  427.         bsr    save_page        ;swapdevice
  428.  
  429.         move.l    d6,d7            ;and now drop through to rob page.
  430.         move.l    d5,a0            ;restore D-table ptr
  431.  
  432. ;---------------
  433.  
  434. rob_page    move.l    #SHORT_INVALID,-(a0)    ;grab page to enable it somewhere else
  435.         and.l    #PTR_MASK,d7        ;isolate RAM page address
  436.         bra    localize_page        ;poof! you're used for other VM page
  437. ;-----------------------------------------------
  438. ; Map RAM page at VM address "naughty_vm_ptr"
  439. ;
  440. ; D7 -> PHYSICAL RAM PAGE
  441. ;-----------------------------------------------
  442. enable_page    or.w    #DT_PAGE,d7        ;turn address into descriptor
  443.  
  444.         move.l    naughty_vm_ptr,d0
  445.         bclr    #31,d0            ;change VM ptr into slot offset
  446.         moveq    #PAGE_SHIFT,d1
  447.         lsr.l    d1,d0            ;d1 = slot number
  448.         move.l    D_tables,a0        ;change MMU table to map new page
  449.         move.l    d7,(a0,d0.l*4)        ;enable new page
  450.         rts
  451. ;-----------------------------------------------
  452. ; Age pages.
  453. ; Using a low priority clock interrupt, go clear the ACCESSED bits in a block
  454. ; of page descriptors. Do so in a circular buffer fashion.
  455. ;-----------------------------------------------
  456. age_pages    move.l    D_tables,a0        ;-> base of D-level tables
  457.         move.l    ager,d0            ;-> circular descr index
  458.         move.w    #4096-1,d1        ;age N descriptors at a time **!!
  459.         move.l    #(1<<(TIB+TIC+TID))-1,d2    ;circular buffer index mask
  460.  
  461. age_em        bclr    #ACCESSED_PAGE,3(a0,d0.l*4)    ;to "age"
  462.         add.l    #1,d0
  463.         and.l    d2,d0            ;keep index inside circular buffer
  464.         dbra    d1,age_em
  465.  
  466.         move.l    d0,ager
  467.         rts
  468. ;-----------------------------------------------
  469. ; Copy a page from VM to disk.
  470. ; A2 -> VM address
  471. ; A3 -> Source Machine address
  472. ;-----------------------------------------------
  473. save_page    move.l    DOS_LIB_PTR,a6        ;using DOS...
  474.  
  475.         move.l    swap_fhandle,d1        ;seek to correct page in file
  476.         move.l    a2,d2
  477.         bclr    #31,d2            ;(turn VM ptr into file offset)
  478.         move.l    #OFFSET_BEGINNING,d3
  479.         DOS    Seek
  480.         
  481.         move.l    swap_fhandle,d1
  482.         move.l    a3,d2            ;write page back to disk
  483.         move.l    #PAGE_SIZE,d3
  484.         DOS    Write
  485.         rts
  486. ;-----------------------------------------------
  487. ; Copy a page from disk to VM.
  488. ;
  489. ; A2 -> VM Address
  490. ; A3 -> Dest Machine address
  491. ;-----------------------------------------------
  492. load_page    movem.l    d2/d3,-(sp)        ;save non-scratch regs
  493.  
  494.         move.l    DOS_LIB_PTR,a6        ;using DOS...
  495.  
  496.         move.l    swap_fhandle,d1        ;seek to correct page in file
  497.         move.l    a2,d2
  498.         bclr    #31,d2            ;(turn VM ptr into file offset)
  499.         move.l    #OFFSET_BEGINNING,d3
  500.         DOS    Seek
  501.         
  502.         move.l    swap_fhandle,d1
  503.         move.l    a3,d2            ;read page from disk
  504.         move.l    #PAGE_SIZE,d3
  505.         DOS    Read
  506.  
  507.         movem.l    (sp)+,d2/d3        ;restore non-scratch regs
  508.         rts
  509. ;-----------------------------------------------
  510. ; Using a block of memory aligned to a 16-byte boundary, initialize it to
  511. ; hold the COMPLETE translation tree for all VM addresses in the range
  512. ; of the requested VM size.
  513. ; This table will become a BRANCH off the A-level table to handle
  514. ; VM addresses only. VM Addresses all have bit 31 SET (e.g $80000000).
  515. ;-----------------------------------------------
  516.  
  517. gen_VM_tree    moveq    #16,d7            ;get RAM aligned to 16-byte boundary
  518.         move.l    #TREE_SIZE,d0        ;A+B+C+D
  519.         bsr    alloc_aligned
  520.         move.l    d0,vm_tree        ;store address of our future MMU table
  521.         beq    no_table
  522. ;---------------
  523.         move.l    d0,a0            ;-> available aligned RAM to fill
  524.         move.l    d0,a1            ;copy
  525.  
  526.         moveq    #0,d0
  527.         bset    #TIA,d0            ;build the one and only A-level table
  528. gen_A_table    move.l    #SHORT_INVALID,(a0)+
  529.         sub.l    #1,d0
  530.         bne    gen_A_table
  531.  
  532.         move.l    a0,B_table        ;remember ptr to VM B-table
  533.  
  534.         move.l    a0,d0
  535.         or.w    #DT_VALID_4BYTE,d0
  536.         move.l    d0,8*4(a1)        ;let table A point to my VM tree
  537. ;---------------
  538.         lea    B_TSIZE(a0),a1        ;-> first C-level table
  539.         move.l    a1,d0
  540.         or.w    #DT_VALID_4BYTE,d0
  541.         move.l    d0,a1            ;descriptor to store in B table
  542.  
  543.         moveq    #0,d0
  544.         bset    #TIB,d0            ;build the one and only B-level table
  545. gen_B_table    move.l    a1,(a0)+        ;store table descriptors to the 16
  546.         add.l    #C_TSIZE,a1        ;C-level tables
  547.         sub.l    #1,d0
  548.         bne    gen_B_table
  549. ;---------------
  550.         move.l    a0,C_tables
  551.  
  552.         moveq    #0,d0
  553.         bset    #TIB+TIC,d0        ;construct 16 C-level tables
  554. gen_C_tables    move.l    a1,(a0)+        ;store descriptors to D-level tables
  555.         add.l    #D_TSIZE,a1
  556.         sub.l    #1,d0
  557.         bne    gen_C_tables        ; (64 entries per table) * 16 tables
  558.  
  559. ;-------------------------------------
  560. ; The D-tables don't contain further table pointers
  561. ; but either PAGE descriptors or INVALID descriptors.
  562. ;-------------------------------------
  563.  
  564.         move.l    a0,D_tables        ;remember where D-level tables are
  565.  
  566.         moveq    #0,d0
  567.         bset    #TIB+TIC+TID,d0        ;construct 16*64 D-level tables
  568. gen_D_tables    move.l    #SHORT_INVALID,(a0)+
  569.         sub.l    #1,d0
  570.         bne    gen_D_tables        ; (8 entries per table)
  571.  
  572.         rts
  573. ;-----------------------------------------------
  574. ; Modify MMU registers CRP and TC to make MMU use my new tree.
  575. ;-----------------------------------------------
  576.  
  577. use_new_tree    move.l    4.w,a6            ;using exec library
  578.  
  579. ;can't have any interrupts using untranslated ROM addresses !
  580.  
  581.         DISABLE
  582.  
  583.         lea    new_MMU_table,a5    ;-> MMU surgery routine
  584.         EXEC    Supervisor
  585.  
  586.         ENABLE                ;re-enable IRQs, multi-tasking etc..
  587.         rts
  588. ;-----------------------------------------------
  589. ; Read current MMU configuration and store values.
  590. ; Construct new MMU register values and poke them (enabling new tree).
  591. ;-----------------------------------------------
  592. new_MMU_table    move.l    vm_tree,a0        ;-> A-table
  593.  
  594.         lea    old_crp_room,a1        ;-> room to store original CRP
  595.         lea    new_crp_room,a2        ;-> room to construct new CRP
  596.         lea    old_tc,a3        ;-> spot to save current TC in
  597.  
  598.         pmove.d    CRP,(a1)         ;get current CRP
  599.         pmove.l    TC,(a3)            ;get current TC
  600.  
  601.         move.l    4(a1),d0        ;get translation table address
  602.         or.w    #DT_VALID_4BYTE,d0    ;turn into a valid table descriptor
  603.         move.l    d0,(a0)            ;store in new A-table
  604.  
  605.         lea    tc_long,a3
  606.         clr.l    (a3)
  607.         pmove.l    (a3),TC            ;disable MMU translation
  608.  
  609. ; The ATC just got flushed.
  610. ; At this point the next PC won't be translated by the MMU
  611. ; but will be used "raw" by the Amiga bus sub-system.
  612.  
  613.         move.l    #$7FFF<<16+DT_VALID_4BYTE,d0    ;no LIMIT for A-table index
  614.         move.l    d0,(a2)
  615.         move.l    a0,4(a2)        ;construct new CRP
  616.         pmove.d    (a2),CRP        ;point MMU to our new tree
  617.  
  618.         move.l    #NEW_TC,(a3)
  619.         pmove.l    (a3),TC            ;re-enable MMU with new table
  620.         rte
  621.  
  622. **********************************************************************************
  623. **********************************************************************************
  624. * This is the core of the program: the 68030 BUS ERROR handler.
  625. * It allows non-existent VM addresses to be used by trapping the generated
  626. * bus errors and modifying the MMU tables and swapping pages in & out of
  627. * physical RAM from/to disk.
  628. **********************************************************************************
  629. **********************************************************************************
  630.  
  631. REGS_BLOCK    equ    (8+8)*4            ;64 bytes for MOVEM.L block
  632.  
  633. ;-----------------------------------------------
  634. bus_err_handler    tst.l    client_Process        ;if we haven't got a VM user...
  635.         beq    normal_bus_err        ;then use normal Exec handler
  636. ;---------------
  637.         movem.l    a0/a1,-(sp)        ;push some regs
  638.         move.l    4.w,a0            ;-> Exec library
  639.  
  640.         move.l    client_Process,a1    ;this Process MUST be our client...
  641.         cmp.l    ThisTask(a0),a1
  642.         bne    pop_n_normal        ;if not let Task handle excep. itself
  643.  
  644.         movem.l    (sp)+,a0/a1        ;restore temp regs
  645. ;---------------
  646.         movem.l    d0-d7/a0-a6,-(sp)    ;don't touch ANY user regs!
  647.         move.l    USP,a0
  648.         move.l    a0,-(sp)        ;note Task's user SP !
  649.  
  650.         lea    REGS_BLOCK(sp),a0    ;-> Bus error exception stack frame
  651.         move.l    $10(a0),naughty_vm_ptr    ;get VM ptr that caused exception
  652.  
  653. ;        lea    $200,a1            ;-> area to dump stack frame in
  654. ;        moveq    #$60-1,d0
  655. ;copy_frame    move.b    (a0)+,(a1)+
  656. ;        dbra    d0,copy_frame
  657.  
  658.         move.w    #$F00,$dff180    ;show sign of exception occurring
  659.         move.w    #$FFF,$dff180    ;show sign of exception occurring
  660.         move.w    #$FFF,$dff180    ;show sign of exception occurring
  661.         move.w    #$FFF,$dff180    ;show sign of exception occurring
  662.         move.w    #$F00,$dff180    ;show sign of exception occurring
  663.         move.w    #$AAA,$dff180
  664.  
  665.     ; Create an RTE frame that will make a Hyperjump to USER code to do all
  666.     ; the neccessary page swapping (loading/saving) and then eventually
  667.     ; switch back to SUPER mode to pop all original regs back and restart the
  668.     ; broken instruction.
  669.  
  670. ;note level of SSP before exiting. If SSP isn't the same when returning: PANIC !
  671.  
  672.         move.l    sp,continue_ssp
  673.  
  674.         move.w    #$0010,-(sp)        ;TYPE+VEC     ;Illegal Inst. frame
  675.         move.l    #add_VM_page,-(sp)     ;PC        ;
  676.         move.w    #$0000,-(sp)           ;SR        ;TT=S=0 and IL = 0 !!
  677.         rte
  678.  
  679.     ; At this point the CPU whizzes off to "add_VM_page" and will eventually
  680.     ; return to finish off this exception at "bus_error_tail".
  681.  
  682. ;-----------------------------------------------
  683. pop_n_normal    movem.l    (sp)+,a0/a1        ;if not: restore regs, go to Exec
  684.  
  685. normal_bus_err    jmp    $F80000            ;**!! SELF-MODIFIED
  686.  
  687.  
  688. ;------------------------------------------------------------------------------------
  689. ; We're nearing the end of our BUS ERROR exception handler.
  690. ; The user code responsible for doing disk accesses has jumped to here via
  691. ; a Supervisor() call.
  692. ; That's just to get us back into supervisor mode, so discard Supervisor RTE
  693. ; frame.
  694. ;
  695. ; **!! Normally, when Tasks call the Supervisor() function they ALWAYS find the
  696. ; SSP pointing to the same spot. The entire VM system relies on this, therefore
  697. ; to avoid crashing due to another Task modifying the level of the supervisor stack
  698. ; we save and restore the SSP, this means that any other Task in the system which
  699. ; messes around with the supervisor stack will get hit by my SSP resets.
  700. ;------------------------------------------------------------------------------------
  701.  
  702. bus_error_tail    move.l    continue_ssp,a7        ;discard Supervisor() stack frame
  703.                         ;(in theory nothing more)
  704.  
  705.     ; At this point the supervisor stack is back in the state we
  706.     ; left it in when switching from SUPER to USER mode with the RTE above.
  707.  
  708.         move.l    (sp)+,a0
  709.         move.l    a0,USP            ;restore user SP
  710.         movem.l    (sp)+,d0-d7/a0-a6    ;restore regs 
  711.         rte                ;restart instruction !
  712.  
  713. ;-----------------------------------------------
  714. ; Allocate and initialize the bitmap which represents the VM pages pool.
  715. ; The VM Pool represents allocated or free VM logical address ranges, it
  716. ; does NOT represent real allocated memory in any way.
  717. ;-----------------------------------------------
  718. init_VM_pool    move.l    vm_bytes,d0        ;get requested VM size (1Mb multiples)
  719.  
  720.         moveq    #PAGE_SHIFT,d1        ;turn into # of pages
  721.         lsr.l    d1,d0
  722.         move.l    d0,vm_total_pages    ;initialize available VM pages
  723.         move.l    d0,vm_pages        ;remember maximum total (constant)
  724.  
  725.         lsr.l    #3,d0            ;= # of bytes for bitmap
  726.         move.l    d0,bitmap_size        ;remember size of bitmap for dealloc
  727.  
  728.         move.l    #MEMF_CLEAR,d1
  729.         move.l    4.w,a6
  730.         EXEC    AllocMem
  731.         move.l    d0,vm_bitmap
  732.         rts                ;return EQ/NE (FAIL/OK)
  733. ;-----------------------------------------------
  734. ; Attempt to allocate a VM block of a given size.
  735. ;
  736. ; D0 = VM block size. (will be rounded up to an integral # of pages)
  737. ;-----------------------------------------------
  738. alloc_VM    movem.l    d2-d7/a2-a6,-(sp)    ;protect non-scratch
  739.  
  740.         add.l    #PAGE_SIZE-1,d0        ;round up to int # of pages
  741.         and.l    #~(PAGE_SIZE-1),d0
  742.  
  743.         move.l    d0,d7            ;remember rounded blocksize
  744.  
  745.         moveq    #PAGE_SHIFT,d1
  746.         lsr.l    d1,d0            ;calc # of pages
  747.  
  748.         cmp.l    vm_total_pages,d0    ;if request is more than available
  749.         bhi    too_big            ;VM : sod off.
  750.  
  751.         move.l    vm_bitmap,a0        ;-> cached bitmap ptr
  752.  
  753.         move.l    d0,d4            ;# of free pages (=bits) to find
  754.         moveq    #0,d5            ;starting looking from bit #0
  755.         move.l    vm_pages,d6
  756.         sub.l    d4,d6            ;max number of "window" positions
  757.         move.l    #VM_START,a5        ;scanning from start of VM...
  758. ;---------------
  759. check_window    move.l    d5,d0            ;is first window bit 0 ?
  760.         bsr    check_bit
  761.         bne    slide_along
  762.  
  763.         move.l    d5,d2            ;yes, check entire window
  764.         move.l    d4,d3            ;(pass starting bitno & window length)
  765.         bsr    check_empty_fld        ;enough contiguous 0s in a row ?
  766.         beq    alloc_window        ;yep, go set them and return VMPTR
  767.  
  768. slide_along    add.l    #1,d5            ;no, check next possible window
  769.         add.l    #PAGE_SIZE,a5        ;in parallel track VMPTR
  770.         sub.l    #1,d6            ;more pages available ?
  771.         bne    check_window
  772.  
  773. too_big        moveq    #0,d0            ;unable to allocate VM block!
  774.         bra    done_alloc
  775. ;---------------
  776. alloc_window    move.l    a5,a1            ;a1-> VM start address (& 7fffffff)
  777.         sub.l    #VM_START,a1
  778.  
  779.         move.l    d7,d0
  780.         bsr    alloc_pages        ;go set bits
  781.  
  782.         move.l    a5,d0            ;return VM address
  783.  
  784. done_alloc    movem.l    (sp)+,d2-d7/a2-a6    ;restore non-scratch registers
  785.         rts
  786. ;-----------------------------------------------
  787. ; Check if VM bitmap bitstring starting at bit position P has N clr bits
  788. ; A0 -> bitmap
  789. ; D2 = starting bit #
  790. ; D3 = # of bits that we want
  791. ; RETURNS : EQ if bitfield is long enough    USES: D0/D1/D2/D3
  792. ;-----------------------------------------------
  793. check_empty_fld    sub.w    #1,d3            ;-1 DBRA
  794.  
  795. check_match    move.l    d2,d0
  796.         add.l    #1,d2
  797.         bsr    check_bit
  798.         dbne    d3,check_match    ;**!! 65536 pages limit
  799.         rts
  800. ;-----------------------------------------------
  801. ; D0 = bit # to check in bitmap            USES: D0/D1
  802. ; A0 -> bitmap
  803. ; RETURNS: EQ/NE for 0/1 bit
  804. ;-----------------------------------------------
  805. check_bit    moveq    #7,d1
  806.         and.w    d0,d1
  807.         not.w    d1            ;d1= bit # in byte
  808.         lsr.l    #3,d0            ;d0= byte #
  809.         btst    d1,0(a0,d0.l)
  810.         rts
  811. ;-----------------------------------------------
  812. ; Free a previously allocated VM block.
  813. ; A1 -> VM address
  814. ; D0 =  block size
  815. ;-----------------------------------------------
  816. free_VM        movem.l    d2-d7/a2-a6,-(SP)
  817.  
  818.         sub.l    #VM_START,a1        ;any ptr has to be a VM ptr !!
  819.         bcc    its_a_VM_ptr
  820.  
  821.         moveq    #-1,d0            ;if top bit was not set: return error
  822.         bra    bad_VMPTR
  823.  
  824. its_a_VM_ptr    add.l    #PAGE_SIZE-1,d0        ;round up to int # of pages
  825.         and.l    #~(PAGE_SIZE-1),d0
  826.  
  827.         moveq    #PAGE_SHIFT,d1
  828.         lsr.l    d1,d0            ;# of page bits to clear
  829.         add.l    d0,vm_total_pages    ;track how much gets freed
  830.  
  831.         move.l    a1,d1            ;-> VM address
  832.         moveq    #PAGE_SHIFT,d2
  833.         lsr.l    d2,d1            ;first page bit # to clear
  834.  
  835.         move.l    D_tables,a3        ;-> base of all D-level page descr
  836.         lea    0(a3,d1.l*4),a3        ;-> 1st page descr of block to free
  837.  
  838.         moveq    #7,d2
  839.         and.w    d1,d2
  840.         eor.w    #7,d2            ;bit # in first byte
  841.  
  842.         lsr.l    #3,d1            ;= bitmap byte offset
  843.         move.l    vm_bitmap,a2        ;-> base of bitmap
  844.         add.l    d1,a2            ;-> byte in bitmap
  845.  
  846.         move.l    4.w,a6            ;in case we need to FreeMem() pages
  847.         move.l    #SHORT_INVALID,d7    ;cached INVALID descriptor
  848.         move.l    #PTR_MASK,d6        ;mask to isolate ptr from descriptor
  849.  
  850.         move.l    d0,d3            ;# of pages to free
  851. ;---------------
  852. dealloc_pages    move.l    (a3),d4            ;get current page descriptor
  853.         bclr    #0,d4
  854.         beq    was_invalid        ;if descriptor contains real page ptr
  855.  
  856.         and.l    d6,d4            ;mask out any non-ptr bits
  857.         move.l    d4,a1            ;-> RAM
  858.         move.l    #PAGE_SIZE,d0        ;free this RAM page as we go
  859.         EXEC    FreeMem        ;**!! RECURSION
  860.  
  861. was_invalid    move.l    d7,(a3)+        ;invalidate descriptor in MMU table
  862.         bclr    d2,(a2)            ;deallocate page bit in bitmap
  863.  
  864.         sub.w    #1,d2            ;dec bitnumber
  865.         bpl    in_byte            ;if wraps from 0 to -1
  866.  
  867.         moveq    #7,d2            ;reset bit # to 7
  868.         add.l    #1,a2            ;and goto next byte in bitmap
  869.  
  870. in_byte        sub.l    #1,d3            ;more pages to free ?
  871.         bne    dealloc_pages
  872. ;---------------
  873.         moveq    #0,d0            ;return OK.
  874. bad_VMPTR    movem.l    (sp)+,d2-d7/a2-a6
  875.         rts
  876. ;-----------------------------------------------
  877. ; Allocate a page range that we've identified as being free.
  878. ; A1 -> VM address (without bit31 set)
  879. ; D0 =  block size
  880. ;-----------------------------------------------
  881. alloc_pages    moveq    #PAGE_SHIFT,d1
  882.         lsr.l    d1,d0            ;# of page bits to clear
  883.         sub.l    d0,vm_total_pages    ;track how many free pages left
  884.  
  885.         move.l    a1,d1
  886.         moveq    #PAGE_SHIFT,d2
  887.         lsr.l    d2,d1            ;first page bit # to clear
  888.  
  889.         moveq    #7,d2
  890.         and.w    d1,d2
  891.         eor.w    #7,d2            ;first bit in byte
  892.  
  893.         lsr.l    #3,d1            ;= bitmap byte offset
  894.         move.l    vm_bitmap,a0
  895.         add.l    d1,a0            ;-> byte in bitmap
  896.  
  897. set_page_bits    bset    d2,(a0)            ;allocate page
  898.  
  899.         sub.w    #1,d2            ;dec bitnumber
  900.         bpl    in_byte2        ;if wraps from 0 to -1
  901.  
  902.         moveq    #7,d2            ;reset bit # to 7
  903.         add.l    #1,a0            ;and goto next byte in bitmap
  904.  
  905. in_byte2    sub.l    #1,d0            ;more bits to set ?
  906.         bne    set_page_bits
  907.         rts
  908. ;-----------------------------------------------
  909. ; Modify system structures to handle new use of VM pointers
  910. ; by a single Process.
  911. ;-----------------------------------------------
  912. install_patches    bsr    gen_VM_tree        ;gen MMU translation tree for VM LAs
  913.         bsr    use_new_tree        ;change MMU to use new, bigger tree
  914.  
  915.         st    hard_patched        ;MMU has been reconfigured !!
  916.  
  917.         move.l    4.w,a6            ;using Exec...
  918.         FORBID
  919.  
  920.         bsr    patch_Exec        ;patch into AllocMem(), FreeMem()
  921.         bsr    patch_DOS        ;patch into Read(), Write()
  922.  
  923.         move.l    $8,normal_bus_err+2    ;our handler passes exception on if
  924.         move.l    #bus_err_handler,$8    ;can't handle it
  925.  
  926.         move.l    4.w,a6            ;using Exec...
  927.         PERMIT
  928.  
  929.         st    soft_patched        ;SYSTEM HAS BEEN MODIFIED !!
  930.         rts
  931. ;-----------------------------------------------
  932. ; Unpatch all VM handling stuff from system.
  933. ; (If patches ever installed)
  934. ;-----------------------------------------------
  935. unpatch_all    move.l    4.w,a6            ;using Exec...
  936.  
  937.         tst.b    soft_patched        ;did we patch it all up ?
  938.         beq    no_soft_patches
  939.  
  940.         FORBID    ;stop others from accessing system in inconsistent state.
  941.  
  942.         move.l    a6,a1
  943.         lea    _LVOAllocMem,a0        ;library entry number
  944.         move.l    normal_alloc+2,d0    ;restore usual vector
  945.         EXEC    SetFunction
  946.  
  947.         move.l    a6,a1
  948.         lea    _LVOFreeMem,a0
  949.         move.l    normal_free+2,d0
  950.         EXEC    SetFunction
  951.  
  952.         move.l    DOS_LIB_PTR,a1
  953.         lea    _LVORead,a0
  954.         move.l    normal_Read+2,d0
  955.         EXEC    SetFunction
  956.  
  957.         move.l    DOS_LIB_PTR,a1
  958.         lea    _LVOWrite,a0
  959.         move.l    normal_Write+2,d0
  960.         EXEC    SetFunction
  961.  
  962.         move.l    normal_bus_err+2,$8    ;restore std Exec exception vector
  963.  
  964.         move.l    4.w,a6
  965.         PERMIT                ;OK: everything's clean again.
  966.  
  967. ;---------------
  968. no_soft_patches    tst.b    hard_patched        ;is VM MMU table active ?
  969.         req
  970.  
  971.         DISABLE
  972.         lea    reset_regs,a5        ;MMU changes in supervisor mode
  973.         EXEC    Supervisor        ;do it..
  974.         ENABLE
  975.         rts
  976. ;---------------------------------------
  977. ; Reset MMU registers to their original values before APPVM.
  978. ;---------------------------------------
  979. reset_regs    lea    tc_long,a0        ;-> room to construct TC register
  980.         clr.l    (a0)
  981.         pmove.l    (a0),TC            ;disable MMU
  982.  
  983.         lea    old_crp_room,a0
  984.         lea    old_tc,a1
  985.  
  986.         pmove.d    (a0),CRP        ;restore original CRP pointer
  987.         pmove.l    (a1),TC            ;re-enable MMU as it was originally
  988.         rte
  989.  
  990. ;-----------------------------------------------
  991. ; Modify the Exec AllocMem() and FreeMem() calls to handle MEMF_VM.
  992. ;-----------------------------------------------
  993. patch_Exec    move.l    4.w,a6
  994.  
  995.         move.l    a6,a1            ;modify exec.library itself
  996.         lea    _LVOAllocMem,a0        ;library entry number
  997.         move.l    #new_AllocMem,d0    ;-> new routine for this entry
  998.         EXEC    SetFunction        ;change library and
  999.         move.l    d0,normal_alloc+2    ;copy usual vector into my jump
  1000.  
  1001.         move.l    a6,a1
  1002.         lea    _LVOFreeMem,a0
  1003.         move.l    #new_FreeMem,d0
  1004.         EXEC    SetFunction        ;same for FreeMem
  1005.         move.l    d0,normal_free+2
  1006.         rts
  1007. ;-----------------------------------------------
  1008. ; Modify the DOS Read() and Write() calls to handle reads and writes from/to VM.
  1009. ;-----------------------------------------------
  1010. patch_DOS    move.l    DOS_LIB_PTR,a1        ;modify dos.library itself
  1011.         lea    _LVORead,a0
  1012.         move.l    #new_Read,d0
  1013.         EXEC    SetFunction        ;install new Read
  1014.         move.l    d0,normal_Read+2
  1015.  
  1016.         move.l    DOS_LIB_PTR,a1
  1017.         lea    _LVOWrite,a0
  1018.         move.l    #new_Write,d0
  1019.         EXEC    SetFunction        ;install new AllocMem
  1020.         move.l    d0,normal_Write+2
  1021.         rts
  1022. ;-----------------------------------------------
  1023. ; Some **!! SELF-MODIFIED code follows here ...
  1024.  
  1025. normal_alloc    jmp    $F80000            ;execute standard AllocMem()
  1026. normal_free    jmp    $F80000            ;execute standard FreeMem()
  1027. normal_Read    jmp    $F80000            ;execute standard Read()
  1028. normal_Write    jmp    $F80000            ;execute standard Write()
  1029.  
  1030. ;-----------------------------------------------
  1031. ; This is our new AllocMem() function.
  1032. ; If the MEMF_VM bit is clear, then just execute normal AllocMem().
  1033. ;
  1034. ; First of all we try to allocate a physical RAM page because the exception handler
  1035. ; assumes that there is always at least one mapped page available to steal if
  1036. ; physical RAM levels are low.
  1037. ; If this succeeds then we check if we've got enough VM left for this request.
  1038. ; If we have then the page gets mapped otherwise the page gets freed again.
  1039. ;
  1040. ; D0 = VM blocksize
  1041. ; D1 = MEMF_VM
  1042. ;-----------------------------------------------
  1043. new_AllocMem    tst.l    d1            ;btst #MEMB_VM,D1
  1044.         bpl    normal_alloc        ;if Process wants some VM,
  1045.  
  1046.         tst.l    client_Process        ;check if we should know this Process.
  1047.         bne    check_client        ;if 1st time call, then
  1048.  
  1049.         move.l    ThisTask(a6),client_Process    ;have this Task as our client
  1050.         clr.l    client_usage        ;initialize its VM usage counter
  1051.         bra    get_vm
  1052.  
  1053. check_client    move.l    client_Process,a0    ;get current client addr
  1054.         cmp.l    ThisTask(a6),a0        ;"Are you the same one, Oh Task ?"
  1055.         bne    bad_client
  1056. ;---------------
  1057. get_vm        movem.l    d7/a2-a3,-(sp)        ;we're a system routine now !!
  1058.         move.l    d0,request_size        ;remember size of requested block
  1059.  
  1060.         move.l    #PAGE_SIZE,d7        ;get RAM aligned to a page boundary
  1061.         move.l    #PAGE_SIZE,d0        ;size of allocation
  1062.         bsr    alloc_aligned        ;get fresh page
  1063.         move.l    d0,d7            ;store addr in parm for enable_page
  1064.         beq    no_initial_page        ;if succeeded,
  1065.  
  1066.         move.l    request_size,d0
  1067.         bsr    alloc_VM        ;handle VM allocation request
  1068.         move.l    d0,naughty_vm_ptr    ;if VM allocation fails, then 
  1069.         bne    got_vm
  1070.  
  1071.         move.l    d7,a1            ;free RAM page and fail totally
  1072.         move.l    #PAGE_SIZE,d0
  1073.         EXEC    FreeMem
  1074.         bra    no_initial_page
  1075. ;---------------
  1076. got_vm        move.l    d0,a2            ;-> VM addr at which
  1077.         move.l    d7,a3            ;RAM page should appear.
  1078.         bsr    load_page        ;fill page from copy on swapdevice
  1079.         bsr    enable_page        ;and change MMU table to enable page
  1080.  
  1081.         move.l    4.w,a6            ;restore EXEC ptr in A6
  1082.  
  1083.         move.l    request_size,d0        ;track client's VM usage so we can
  1084.         add.l    d0,client_usage        ;free client when freeing all.
  1085.  
  1086.         move.l    naughty_vm_ptr,d0    ;return VM ptr
  1087.         movem.l    (sp)+,d7/a2-a3        
  1088.         rts
  1089.  
  1090. ;---------------
  1091. no_initial_page    movem.l    (sp)+,d7/a2-a3        ;restore non-scratch register
  1092.  
  1093. bad_client    moveq    #0,d0            ;sorry, VM used by other Process
  1094.         rts
  1095. ;-----------------------------------------------
  1096. ; This is our new FreeMem() function.
  1097. ; If the address of the returned block is not a VM address, then just
  1098. ; execute normal FreeMem().
  1099. ;
  1100. ; D0 = VM blocksize
  1101. ; A1 -> VM Block
  1102. ;-----------------------------------------------
  1103. new_FreeMem    move.l    a1,test_ptr        ;test if ptr is a VMPTR
  1104.         bpl    normal_free        ;yes,
  1105.  
  1106.         tst.l    client_Process        ;Process HAS to be our client.
  1107.         beq    VM_FreeMem_err        ;impossible not to know him.
  1108.  
  1109.         move.l    client_Process,a0    ;get current client addr
  1110.         cmp.l    ThisTask(a6),a0        ;"Are you the same one, Oh Task ?"
  1111.         bne    VM_FreeMem_err
  1112.  
  1113.         sub.l    d0,client_usage        ;when client FreeVM()s all
  1114.         bne    holding_VM        ;open door to new client
  1115.         clr.l    client_Process        ;client has no more VM: goodbye!
  1116.  
  1117. holding_VM    bsr    free_VM
  1118.  
  1119. VM_FreeMem_err    rts
  1120.  
  1121. ;-----------------------------------------------
  1122. ; This is our new AmigaDOS Read() function.
  1123. ; If the address of the buffer is not a VM address, then just
  1124. ; execute normal Read().
  1125. ;
  1126. ; D1 = filehandle
  1127. ; D2 = buffer (possibly VM ptr)
  1128. ; D3 = size of buffer to fill
  1129. ;-----------------------------------------------
  1130. new_Read    tst.l    d2            ;test if ptr is a VMPTR
  1131.         bpl    normal_Read        ;yes,
  1132.  
  1133.         move.l    client_Process,a0    ;get current client addr (even if NULL)
  1134.         move.l    4.w,a1
  1135.         cmp.l    ThisTask(a1),a0        ;"Are you the same one, Oh Task ?"
  1136.         bne    alien_uses_VM
  1137.  
  1138.         movem.l    d2-d7/a2-a6,-(sp)    ;protect all non-scratch regs !
  1139.  
  1140.         move.l    DOS_LIB_PTR,a6        ;in case Task is naughty !
  1141.         move.l    d1,a5            ;filehandle
  1142.         move.l    d2,d4            ;VM destination
  1143.         move.l    d3,d5            ;# of bytes to transfer
  1144.         bsr    VM_READ
  1145.  
  1146.         move.l    d7,d0            ;return # of bytes successfully read
  1147.  
  1148.         movem.l    (sp)+,d2-d7/a2-a6
  1149.         rts
  1150.  
  1151. alien_uses_VM    moveq    #0,d0            ;no bytes read: ERROR.
  1152.         rts
  1153.  
  1154. ;-----------------------------------------------
  1155. ; This is our new AmigaDOS Write() function.
  1156. ; If the address of the buffer is not a VM address, then just
  1157. ; execute normal Write().
  1158. ;
  1159. ; D1 = filehandle
  1160. ; D2 = buffer (possibly VM ptr)
  1161. ; D3 = size of buffer to save
  1162. ;-----------------------------------------------
  1163. new_Write    tst.l    d2            ;test if ptr is a VMPTR
  1164.         bpl    normal_Write        ;yes,
  1165.  
  1166.         move.l    client_Process,a0    ;get current client addr
  1167.         move.l    4.w,a1
  1168.         cmp.l    ThisTask(a1),a0        ;"Are you the same one, Oh Task ?"
  1169.         bne    alien_uses_VM
  1170.  
  1171.         movem.l    d2-d7/a2-a6,-(sp)    ;protect all non-scratch regs !
  1172.  
  1173.         move.l    DOS_LIB_PTR,a6        ;in case Task is naughty !
  1174.         move.l    d1,a5            ;filehandle
  1175.         move.l    d2,d4            ;VM destination
  1176.         move.l    d3,d5            ;# of bytes to transfer
  1177.         bsr    VM_WRITE
  1178.  
  1179.         movem.l    (sp)+,d2-d7/a2-a6
  1180.         move.l    d3,d0            ;return # of bytes successfully write
  1181.         rts
  1182.  
  1183. ;-----------------------------------------------------------------------------------
  1184. ; Read N bytes from any file into VM.
  1185. ; Parts of the read going to VM which isn't currently mapped are transferred
  1186. ; straight to the swapfile.
  1187. ; Worst case: No mapped VM exists and we have to do a file_to_file copy.
  1188. ; Best case: All VM is mapped to RAM and we just fill in all these pages.
  1189. ; A5 -> filehandle
  1190. ; D4 = VM destination
  1191. ; D5 = bytes to read
  1192. ; A6 = DOS_LIB_PTR
  1193. ;
  1194. ; RETURN: bytes read in D7
  1195. ;-----------------------------------------------------------------------------------
  1196.  
  1197. VM_READ        moveq    #0,d7            ;0 bytes read so far..
  1198.  
  1199.         bclr    #31,d4            ;VMPTR to byte offset
  1200.         move.l    d4,d0            ; = byte offset
  1201.  
  1202.         moveq    #PAGE_SHIFT,d1
  1203.         lsr.l    d1,d0            ; = starting page #
  1204.  
  1205.         move.l    D_tables,a4        ;-> base of D-table page descr.
  1206.         lea    0(a4,d0.l*4),a4        ;-> first page descr of destination
  1207.  
  1208.         move.l    #PAGE_SIZE-1,d0        ;is there an un-aligned portion
  1209.         and.l    d4,d0            ;to read at all ?
  1210.         beq    no_head
  1211. ;---------------
  1212.         move.l    #PAGE_SIZE,d1
  1213.         sub.l    d0,d1            ;max # of head bytes to read
  1214.  
  1215.         cmp.l    d5,d1            ;is # of bytes smaller than this ?
  1216.         bcs    head_num_ok        ;yes,
  1217.         move.l    d5,d1            ;then read that few instead
  1218.  
  1219. head_num_ok    sub.l    d1,d5            ;decr total to read left
  1220.  
  1221.         move.l    (a4)+,d2        ;get page descriptor
  1222.         bmi    external_page0
  1223.  
  1224.         and.l    #PTR_MASK,d2        ;turn into valid machine ptr
  1225.  
  1226.         add.l    d0,d2            ;point to correct read spot
  1227.  
  1228.         move.l    d1,d3            ;Read() N bytes
  1229.         move.l    a5,d1            ;from user file
  1230.         DOS    Read            ;straight into physical RAM
  1231.         add.l    d0,d7            ;track bytes successfully read
  1232.  
  1233.         cmp.l    d3,d0            ;if we read less than requested, then
  1234.         beq    align_offset        ;we've reached EOF, so exit here
  1235.         rts
  1236. ;-----
  1237. external_page0    move.l    a5,a2            ;from user file
  1238.         move.l    swap_fhandle,a3        ;to swapfile
  1239.         move.l    d4,d2            ;at VM offset
  1240.         move.l    d1,d3            ;copy N bytes
  1241.         bsr    file_to_file
  1242.         add.l    d0,d7
  1243.  
  1244.         cmp.l    d3,d0
  1245.         beq    align_offset
  1246.         rts
  1247.  
  1248. align_offset    add.l    #PAGE_SIZE-1,d4
  1249.         and.l    #~(PAGE_SIZE-1),d4    ;align VM offset to page boundary
  1250. ;---------------
  1251. no_head        tst.l    d5            ;any more bytes to read ?
  1252.         beq    VM_read_done
  1253.  
  1254.         move.l    #~(PAGE_SIZE-1),d6    ;any integral # of pages to read ?
  1255.         and.l    d5,d6
  1256.         beq    no_body
  1257.  
  1258.         moveq    #PAGE_SHIFT,d1
  1259.         lsr.l    d1,d6            ;# of whole pages to "load"
  1260.  
  1261. read_pages    move.l    (a4)+,d2        ;get page descriptor
  1262.         bmi    external_page1        ;if page is mapped,
  1263. ;---------------
  1264.         and.l    #PTR_MASK,d2        ;turn descr into valid machine ptr
  1265.  
  1266.         move.l    #PAGE_SIZE,d3        ;Read() N bytes
  1267.         move.l    a5,d1            ;from user file
  1268.         DOS    Read            ;straight into physical RAM
  1269.         add.l    d0,d7            ;track bytes successfully read
  1270.  
  1271.         cmp.l    d3,d0            ;if we read less than requested, then
  1272.         beq    rd_next_page        ;we've reached EOF, so exit here
  1273.         rts
  1274.  
  1275. external_page1    move.l    a5,a2            ;from user file
  1276.         move.l    swap_fhandle,a3        ;to swapfile
  1277.         move.l    d4,d2            ;at VM offset
  1278.         move.l    #PAGE_SIZE,d3        ;copy exactly one page
  1279.         bsr    file_to_file
  1280.         add.l    d0,d7
  1281.  
  1282.         cmp.l    d3,d0
  1283.         beq    rd_next_page
  1284.         rts
  1285.  
  1286. rd_next_page    add.l    #PAGE_SIZE,d4        ;keep track of VM read offset
  1287.         sub.l    #PAGE_SIZE,d5        ;track how much left to read
  1288.         sub.l    #1,d6            ;more pages to read ?
  1289.         bne    read_pages
  1290. ;---------------
  1291. no_body        tst.l    d5            ;any more bytes to read ?
  1292.         beq    VM_read_done
  1293.  
  1294.         move.l    (a4)+,d2        ;get page descriptor
  1295.         bmi    external_page2
  1296.  
  1297.         and.l    #PTR_MASK,d2        ;turn descr into valid machine ptr
  1298.  
  1299.         move.l    d5,d3            ;Read() last N bytes
  1300.         move.l    a5,d1            ;from user file
  1301.         DOS    Read            ;straight into physical RAM
  1302.         add.l    d0,d7            ;track bytes successfully read
  1303.         rts
  1304.  
  1305. external_page2    move.l    a5,a2            ;from user file
  1306.         move.l    swap_fhandle,a3        ;to swapfile
  1307.         move.l    d4,d2            ;at VM offset
  1308.         move.l    d5,d3            ;copy remaining bytes
  1309.         bsr    file_to_file
  1310.         add.l    d0,d7
  1311.  
  1312. VM_read_done    rts
  1313.  
  1314. ;-----------------------------------------------------------------------------------
  1315. ; Write N bytes from VM to any file.
  1316. ; Parts of the write from VM which aren't currently mapped are treated as
  1317. ; no-ops (the page/bytes should already be on the disk !).
  1318. ; Best case: No mapped VM exists, so we don't do anything.
  1319. ; Worse case: All VM is mapped to RAM and we have to write all these pages.
  1320. ; A5 -> filehandle
  1321. ; D4 = VM source
  1322. ; D5 = bytes to write
  1323. ; A6 = DOS_LIB_PTR
  1324. ;-----------------------------------------------------------------------------------
  1325.  
  1326. VM_WRITE:    bclr    #31,d4            ;VMPTR to byte offset
  1327.         move.l    d4,d7            ; = byte offset
  1328.  
  1329.         moveq    #PAGE_SHIFT,d0
  1330.         lsr.l    d0,d7            ; = starting page #
  1331.  
  1332.         move.l    D_tables,a4        ;-> base of D-table page descr.
  1333.         lea    0(a4,d7.l*4),a4        ;-> first page descr of destination
  1334.  
  1335.         move.l    #PAGE_SIZE-1,d0        ;is there an un-aligned portion
  1336.         and.l    d4,d0            ;to read at all ?
  1337.         beq    no_head_wr
  1338. ;---------------
  1339.         move.l    #PAGE_SIZE,d1
  1340.         sub.l    d0,d1            ;max # of head bytes to read
  1341.  
  1342.         cmp.l    d5,d1            ;is # of bytes smaller than this ?
  1343.         bcs    head_num_ok2        ;yes,
  1344.         move.l    d5,d1            ;then read that few instead
  1345.  
  1346. head_num_ok2    sub.l    d1,d5            ;decr total to read left
  1347.  
  1348.         move.l    (a4)+,d2        ;get page descriptor
  1349.         bmi    align_offset2        ;only if page is valid
  1350.  
  1351.         and.l    #PTR_MASK,d2        ;turn into valid machine ptr
  1352.  
  1353.         add.l    d0,d2            ;point to correct read spot
  1354.  
  1355.         move.l    d1,d3            ;Write() N bytes
  1356.         move.l    a5,d1            ;to user file
  1357.         DOS    Write            ;straight from physical RAM
  1358. ;-----
  1359. align_offset2    add.l    #PAGE_SIZE-1,d4
  1360.         and.l    #~(PAGE_SIZE-1),d4    ;align VM offset to page boundary
  1361. ;---------------
  1362. no_head_wr    tst.l    d5            ;any more bytes to write ?
  1363.         beq    VM_write_done
  1364.  
  1365.         move.l    #~(PAGE_SIZE-1),d6    ;any integral # of pages to write ?
  1366.         and.l    d5,d6
  1367.         beq    no_body2
  1368.  
  1369.         moveq    #PAGE_SHIFT,d1
  1370.         lsr.l    d1,d6            ;# of whole pages to "load"
  1371.  
  1372. write_pages    move.l    (a4)+,d2        ;get page descriptor
  1373.         bmi    wr_next_page        ;only if page is mapped,
  1374. ;---------------
  1375.         and.l    #PTR_MASK,d2        ;turn descr into valid machine ptr
  1376.  
  1377.         move.l    #PAGE_SIZE,d3        ;Write() N bytes
  1378.         move.l    a5,d1            ;to user file
  1379.         DOS    Write            ;straight from physical RAM
  1380.  
  1381. wr_next_page    add.l    #PAGE_SIZE,d4        ;keep track of VM read offset
  1382.         sub.l    #PAGE_SIZE,d5        ;track how much left to read
  1383.         sub.l    #1,d6            ;more pages to write ?
  1384.         bne    write_pages
  1385. ;---------------
  1386. no_body2    tst.l    d5            ;any more bytes to read ?
  1387.         beq    VM_write_done
  1388.  
  1389.         move.l    (a4)+,d2        ;get page descriptor
  1390.         bmi    VM_write_done        ;only if page is mapped,
  1391.  
  1392.         and.l    #PTR_MASK,d2        ;turn descr into valid machine ptr
  1393.  
  1394.         move.l    d5,d3            ;Read() last N bytes
  1395.         move.l    a5,d1            ;from user file
  1396.         DOS    Write            ;straight into physical RAM
  1397.  
  1398. VM_write_done    rts
  1399.  
  1400. ;-----------------------------------------------------------------------------------
  1401. ; Copy N bytes from src file to another at a specific dest position.
  1402. ;
  1403. ; A2 -> Source FileHandle (fh1)    (file ptr position IMPLICIT)
  1404. ; A3 -> Dest   FileHandle (fh2)    (file ptr position EXPLICIT)
  1405. ;
  1406. ; D2 =  Position to Seek to in Destination File
  1407. ; D3 =  total # of bytes to copy
  1408. ;
  1409. ; INTERNALLY:    D7 = original buff size
  1410. ;        D4 -> chunk buffer
  1411. ;        D5 = chunk buffer size
  1412. ;
  1413. ; RETURN: D0 = number of bytes really transferred
  1414. ;-----------------------------------------------------------------------------------
  1415.  
  1416. file_to_file    movem.l    d2-d7/a2-a6,-(sp)    ;protect non-scratch registers
  1417.  
  1418.         move.l    d2,d0            ;check that copy operation
  1419.         add.l    d3,d0            ;fits entirely inside swapfile!
  1420.         cmp.l    vm_bytes,d0    ;**!! SHOULD NEVER OCCUR
  1421.         bhi    copy_impossible        ;yes, it won't overflow swapfile so
  1422. ;---------------
  1423.         move.l    4.w,a6            ;using Exec..
  1424.  
  1425.         move.l    d3,d7            ;remember original size
  1426.         bra    try_largest        ;try to get largest poss. copy buffer
  1427. ;---------------
  1428. buf_too_big    lsr.l    #1,d3            ;attempt block half as big then...
  1429.  
  1430. try_largest    move.l    d3,d0            ;attempt buffer of this size
  1431.         move.l    #MEMF_PUBLIC,d1        ;FAST RAM please ! (if possible)
  1432.         EXEC    AllocMem
  1433.         move.l    d0,d4            ;did allocation succeed ?
  1434.         beq    buf_too_big        ;OK we've got a block of size N
  1435. ;---------------
  1436.         move.l    d3,d5            ;remember chunk size
  1437.  
  1438.         moveq    #0,d6            ;no bytes transferred so far.
  1439.  
  1440.         move.l    DOS_LIB_PTR,a6        ;using DOS...
  1441.  
  1442.         move.l    a3,d1            ;set fileptr of destination file
  1443.         ;    ;            ;D2 = original argument !
  1444.         move.l    #OFFSET_BEGINNING,d3
  1445.         DOS    Seek            ;dest fileptr to start of copy pos
  1446.  
  1447.         move.l    d4,d2            ;set TO/FROM buffer ptr (constant)
  1448.         move.l    d5,d3            ;set transfer size (constant)
  1449. ;---------------
  1450. copy_chunk    move.l    a2,d1            ;Read() a chunk of huge block into
  1451.         DOS    Read            ;copy work buffer
  1452.         add.l    d0,d6            ;track # of bytes transferred
  1453.  
  1454.         move.l    a3,d1            ;Write() a chunk of huge block out
  1455.         move.l    d0,d3            ;or less if premature EOF encountered
  1456.         beq    ff_transf_done
  1457.         DOS    Write            ;to destination file
  1458.  
  1459.         sub.l    d5,d7            ;track howmany bytes copied so far
  1460.         cmp.l    d5,d7            ;can we do another chunk copy ?
  1461.         bhi    copy_chunk
  1462. ;---------------
  1463.         move.l    d7,d3
  1464.         beq    perfect_fit        ;if any extra bytes to do,
  1465.  
  1466.         move.l    a2,d1            ;copy left overs too..
  1467.         DOS    Read            ;read in MOD chunksize bytes
  1468.         add.l    d0,d6            ;track how many bytes transferred
  1469.  
  1470.         move.l    a3,d1
  1471.         move.l    d0,d3
  1472.         DOS    Write            ;and copy them out again
  1473. ;---------------
  1474. perfect_fit    move.l    4.w,a6            ;return temporary copy buffer!
  1475.         move.l    d4,a1
  1476.         move.l    d5,d0
  1477.         EXEC    FreeMem
  1478.  
  1479. ff_transf_done    move.l    d6,d0            ;return # of bytes actually copied
  1480.         movem.l    (sp)+,d2-d7/a2-a6
  1481.         rts
  1482.  
  1483. copy_impossible    moveq    #0,d0            ;return FAIL. Not enough VM.
  1484.         movem.l    (sp)+,d2-d7/a2-a6
  1485.         rts
  1486.  
  1487. ;-----------------------------------------------
  1488. ; Open libraries, console handle, init defaults
  1489. ;-----------------------------------------------
  1490. init_all    clr.l    client_Process        ;no Task using our VM yet..
  1491.         clr.l    ager            ;reset descriptor ageing index
  1492.  
  1493.         sf    soft_patched        ;don't touch system when "unpatching"!
  1494.         sf    hard_patched        ;don't stuff invalid values in MMU
  1495.  
  1496.         move.l    4.w,a6            ;using Exec...
  1497.  
  1498.         lea    dosname,a1
  1499.         moveq    #0,d0
  1500.         EXEC    OpenLibrary        ;open DOS
  1501.         move.l    d0,DOS_LIB_PTR
  1502.         beq    END_APPVM
  1503.  
  1504.         move.l    d0,a6
  1505.         DOS    Output            ;get stdout handle
  1506.         move.l    d0,stdout
  1507.         rts
  1508. ;-----------------------------------------------
  1509. ; Free libraries, handles...
  1510. ;-----------------------------------------------
  1511. close_all    move.l    DOS_LIB_PTR,d0        ;did we ever get DOS ?
  1512.         beq    no_dos            ;yes,
  1513.  
  1514.         move.l    d0,a6            ;then close swapfile first
  1515.         move.l    swap_fhandle,d1        ;if we ever got that file
  1516.         beq    no_swaphandle
  1517.         DOS    Close
  1518.  
  1519. no_swaphandle    move.l    a6,a1            ;then close library itself
  1520.  
  1521.         move.l    4.w,a6
  1522.         EXEC    CloseLibrary
  1523. ;---------------
  1524. no_dos
  1525. dummy        rts
  1526.  
  1527. ;-----------------------------------------------
  1528. ; D0 = size of block to get
  1529. ; D7 = block should be aligned to ... byte boundary (powers of two!)
  1530. ;
  1531. ; This is done by first attempting to allocate a block that is guaranteed
  1532. ; to CONTAIN a block with the correct alignment, noting that base address,
  1533. ; then doing an AllocAbs() of the aligned block inside that block.
  1534. ;-----------------------------------------------
  1535.  
  1536. alloc_aligned    movem.l    d2-d7/a2-a6,-(sp)
  1537.  
  1538.         move.l    4.w,a6            ;using Exec
  1539.         FORBID                ;disable allocs between Free & AllocAbs
  1540.  
  1541.         move.l    d0,d6            ;remember original requested size
  1542.  
  1543.         add.l    d7,d0            ;incr. blocksize to get a size which
  1544.         move.l    d0,d3            ;guarantees a contained aligned base
  1545.  
  1546.         move.l    #MEMF_PUBLIC,d1        ;attempt to get this block which
  1547.         EXEC    AllocMem        ;encloses the block we really want.
  1548.         move.l    d0,d2
  1549.         beq    fail_alloc
  1550. ;---------------
  1551.         move.l    d3,d0            ;ok, now release this "test" block
  1552.         move.l    d2,a1
  1553.         EXEC    FreeMem            ;and from its base address
  1554.  
  1555.         sub.l    #1,d7            ;calc address of aligned block
  1556.         add.l    d7,d2
  1557.         not.l    d7
  1558.         and.l    d7,d2            ;-> aligned ptr
  1559.         move.l    d2,a1
  1560.         move.l    d6,d0
  1561.         EXEC    AllocAbs        ;in theory this call cannot fail !
  1562.         move.l    d0,d2
  1563.         PERMIT
  1564.         move.l    d2,d0            ;return ptr or NULL
  1565.         movem.l    (sp)+,d2-d7/a2-a6
  1566.         rts
  1567.  
  1568. fail_alloc    PERMIT
  1569.         moveq    #0,d0            ;aligned allocation FAILED
  1570.         movem.l    (sp)+,d2-d7/a2-a6
  1571.         rts
  1572. ;-----------------------------------------------
  1573.         include    "SRC:UTILS/ReadArgs.s"
  1574.         include    "SRC:MODULES/LIB1/DEC_TO_BIN"
  1575.  
  1576. ;-----------------------------------------------
  1577. ; Program Strings, Constants
  1578. ;-----------------------------------------------
  1579.  
  1580. no_table_str        dc.b    "Couldn't allocate new MMU translation tables!",0
  1581. give_example_str    dc.b    "Example: APPVM 20 SWAPFILE DEVS:swapfile",0
  1582. too_much_vm_str        dc.b    "Kindly request less than 256 Megabytes for VM management.",0
  1583. not_enough_vm_str    dc.b    "Kindly request at least 1 Megabyte.",0
  1584. no_VM_init_str        dc.b    "Not enough memory to initialise VM pool.",0
  1585. unable_to_create_str    dc.b    "Could not create swapfile.",0
  1586. disk_full_str        dc.b    "Not enough room on disk for swapfile.",0
  1587. resident_str        dc.b    "APPVM is already active.",0
  1588. need_MMU_str        dc.b    "APPVM requires an MMU to enable Virtual Memory.",0
  1589.  
  1590. dosname        DOSNAME
  1591.  
  1592. default_swfn    dc.b    "Work:T/SWAPFILE",0
  1593.  
  1594. vm_node_name    dc.b    "VM_NODE",0
  1595.  
  1596. APPVM_template    dc.b    "VMMEGS/A,SWAPFILE/K",0
  1597.  
  1598. VM_ready    dc.b    LF,"Virtual Memory Manager 0.9 "
  1599.         dc.b    ESC,"[7m"            ;HIGHLIGHT ON
  1600.         dc.b    "Ready"
  1601.         dc.b    ESC,"[0m"            ;HIGHLIGHT OFF
  1602.         dc.b    LF
  1603.         dc.b    "Written by Laurence Vanhelsuwé © March 1992",0
  1604.  
  1605. VM_off        dc.b    LF,"Virtual Memory Manager no longer active.",LF,0
  1606.  
  1607. appVM_version    dc.b    "$VER: APPVM 0.9 ©LVA (Alpha release) 27/MAR/92",0
  1608.         dc.b    "Copyright material, see user license for details.",0
  1609.  
  1610. ;-----------------------------------------------
  1611. ;Program variables, pointers, flags
  1612. ;-----------------------------------------------
  1613.  
  1614. arg_line    ds.l    1    ;-> raw arguments
  1615. stack_level    ds.l    1    ;program launch SP
  1616.  
  1617. DOS_LIB_PTR    ds.l    1    ;-> opened dos.library
  1618. stdout        ds.l    1    ;-> console file
  1619.  
  1620. swap_fhandle    ds.l    1    ;file handle for swapfile
  1621.  
  1622. continue_ssp    ds.l    1    ;exception handler SSP level (SSP must remain same)
  1623.  
  1624. client_Process    ds.l    1    ;-> NULL or ONLY Task/Process which is using VM
  1625. client_usage    ds.l    1    ; # of VM bytes client is using at this moment.
  1626.  
  1627. test_ptr    ds.l    1    ;a LONG to test ptr in A reg without using regs
  1628. naughty_vm_ptr    ds.l    1    ;VMPTR that caused bus error exception
  1629. request_size    ds.l    1    ;for AllocVM() to remember # of bytes
  1630.  
  1631. vm_tree        ds.l    1    ;-> root of tree (A-level table)
  1632.  
  1633. B_table        ds.l    1    ;-> one and only VM B-table
  1634. C_tables    ds.l    1
  1635. D_tables    ds.l    1    ;-> ptr to INVALID descriptors and valid PAGE descr.
  1636. ager        ds.l    1    ;index into descriptors
  1637.  
  1638. old_crp_room    ds.l    2    ;room to store current 64-bit CRP register
  1639. old_tc        ds.l    1    ;same for TC
  1640.  
  1641. new_crp_room    ds.l    2    ;room to store future  64-bit CRP register
  1642. tc_long        ds.l    1
  1643.  
  1644. ; VM Pool management variables
  1645. ; ----------------------------
  1646. vm_bytes    ds.l    1    ;size of VM in bytes (rounded)
  1647. vm_total_pages    ds.l    1    ;total amount of VM pages remaining
  1648. vm_pages    ds.l    1    ;total amount of VM pages (constant **!!)
  1649. vm_bitmap    ds.l    1    ;-> allocated pages bitmap
  1650. bitmap_size    ds.l    1    ;size of above
  1651. pages_mapped    ds.l    1 **!!
  1652.  
  1653. ; ReadArgs() results array
  1654. ; ------------------------
  1655.         EVEN
  1656. appvm_results
  1657. vm_megs        ds.l    1
  1658. swap_filename    ds.l    1
  1659.  
  1660. ; Flags
  1661. ; -----
  1662. soft_patched    ds.b    1    ;tell unpatch_all to undo work..
  1663. hard_patched    ds.b    1    ;restore old MMU configuration
  1664.  
  1665.         END
  1666.